This is a race bug.
This bug is very hard to reproduce because its buggy window is very narrow. So a short pause is
added to the buggy source's byte code to extend the window.
More details about this bug are at
JDK-4779253 JIRA page.
java.util.logging.Logger
t1 t2 public void log(LogRecord record) {
if (record.getLevel().intValue() < levelValue || levelValue == offValue) {
return;
}
synchronized (this) {
1,3 if (filter != null && !filter.isLoggable(record)) {
return;
}
}
}
public void setFilter(Filter newFilter) throws SecurityException {
checkAccess();
2 filter = newFilter;
}
Precondition:
filter has been initialized to some instance.
a) thread 1 enters synchronized block to check if filter is null at 1. As mentioned in precondition,
filter is not null,so it continues to check the second condition.
b) just before thread 1 starts to check the second condition, context switched, thread 2 set filter to
newFilter at 2. Although line 1 is protected by synchronized block, there is no such protection
at line 2, filter is still free to alter at 2. Here newFilter is null, and filter is set to null.
c) context switched, thread 1 continues to check the second condition after "&&". But now filter is null,
so a NullpointerException is thrown out.
This bug is reproduced under JDK 1.6.0 and JDK 1.6.0_33.
It started at JDK 1.6.0, and has been fixed since JDK 1.7.0.
Execute the following scripts to run the test to reproduce the bug (assume the location of the jdk6 test project is jdk_test_home).
Linux:
${jdk_test_home}/scripts/4779253.sh [--javaloc path] [--sleepTime value]
Windows:
%jdk_test_home%\scripts\4779253.bat [--javaloc path] [--sleepTime value]
Example:
The default number of sleepTime is 1000 if not specified. For example:
${jdk_test_home}/scripts/4779253.sh
is the same as:
${jdk_test_home}/scripts/4779253.sh --sleepTime 1000
| Option | Function |
| --sleepTime, -st | milliseconds to sleep between two condition checks where race could happen. Default value is 1000 if this option is not set explicitly. |
| --javaloc | The location of JDK that is eligible to reproduce the bug, if your java environment is not eligible.
In this case, it's JDK 1.6.0. It should be the absolute path to the JDK's java starter and ended with "/". For example: ~/jdk/home/jdk1.6.0/bin/ |